﻿using AutoMapper.Configuration;
using HDS.Admin.Api.ViewModels.Mapping;
using HDS.Common.Helper;
using HDS.IService.Log;
using HDS.IService.Master;
using HDS.Model;
using HDS.Model.Entity.Log;
using HDS.Model.Entity.Master;
using HDS.Model.Entity.View;
using LinqKit;
using Microsoft.AspNetCore.Cors;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Claims;
using System.Threading.Tasks;

namespace HDS.Admin.Api.Controllers
{
    [Route("[controller]/[action]")]
    [ApiController]
    [EnableCors]
    public class MappingController : AdminController
    {
        private readonly ILogger<MappingController> _logger;
        private readonly IMappingService _imappingService;
        private readonly IUpdateLogService _iupdateLogService;
        private readonly IHotelService _ihotelService;
        private readonly ISupplierHotelService _isupplierHotelService;

        public MappingController(ILogger<MappingController> logger, IMappingService imappingService, IUpdateLogService iupdateLogService, IHotelService ihotelService, ISupplierHotelService isupplierHotelService)
        {
            _logger = logger;
            _imappingService = imappingService;
            _iupdateLogService = iupdateLogService;
            _ihotelService = ihotelService;
            _isupplierHotelService = isupplierHotelService;
        }

        public async Task<ResultData<DataPagingModel<VMappingHotelOpt>>> GetMappingPageList([FromBody] SearchDto searchDto)
        {
            var hotelNameEn = (searchDto.HotelName ?? "").IsEnglish() ? searchDto.HotelName : "";
            var hotelNameCn = (searchDto.HotelName ?? "").IsEnglish() ? "" : searchDto.HotelName;

            var predicate = PredicateBuilder.New<VMappingHotelOpt>(true);
            if (searchDto.HotelId.HasValue)
                predicate = predicate.And(e => e.HotelId == searchDto.HotelId);
            if (searchDto.HotelStar.HasValue)
                predicate = predicate.And(e => e.HotelStar == searchDto.HotelStar);
            if (!string.IsNullOrEmpty(hotelNameEn))
                predicate = predicate.And(e => e.HotelNameEn.Contains(hotelNameEn.Trim()));
            if (!string.IsNullOrEmpty(hotelNameCn))
                predicate = predicate.And(e => e.HotelNameCn.Contains(hotelNameCn.Trim()));
            if (!string.IsNullOrEmpty(searchDto.CountryName))
                predicate = predicate.And(e => e.CountryName.Contains(searchDto.CountryName.Trim()));
            if (!string.IsNullOrEmpty(searchDto.CityName))
                predicate = predicate.And(e => e.CityName.Contains(searchDto.CityName.Trim()));
            if (!string.IsNullOrEmpty(searchDto.Supplier))
                predicate = predicate.And(e => e.Supplier.Equals(searchDto.Supplier));
            if (!string.IsNullOrEmpty(searchDto.SupplierHotelId))
                predicate = predicate.And(e => e.SupplierHotelId.Equals(searchDto.SupplierHotelId.Trim()));
            if (searchDto.IsAvail.HasValue)
            {
                if(searchDto.IsAvail.Value)
                    predicate = predicate.And(e => e.IsAvail.Equals(searchDto.IsAvail));
                else
                    predicate = predicate.And(e => e.IsAvail == false || e.IsAvail == null);
            }
            if (searchDto.IsTop.HasValue)
            {
                if(searchDto.IsTop.Value)
                    predicate = predicate.And(e => e.SupplierTop > 0);
                else
                    predicate = predicate.And(e => e.SupplierTop <= 0 || e.SupplierTop == null);
            }
            if (searchDto.IsMapping.HasValue)
            {
                if (searchDto.IsMapping.Value)
                    predicate = predicate.And(e => e.HotelId > 0);
                else
                    predicate = predicate.And(e => e.HotelId == null);
            }

            var dataPaging = await _imappingService.GetVMappingHotels(searchDto.PageIndex, searchDto.PageSize, predicate, "");

            return new ResultData<DataPagingModel<VMappingHotelOpt>> { Success = true, Data = dataPaging };
        }

        public async Task<ResultData<List<VMappingHotel>>> GetMappingList(int HotelId)
        {
            var list = await _imappingService.GetVMappingHotels(HotelId);

            return new ResultData<List<VMappingHotel>>
            {
                Success = true,
                Data = list
            };
        }

        public async Task<ResultData<string>> SaveMapping(int hotelId, string supplier, string supplierHotelId)
        {
            var entity = new MappingHotel { 
                Id = 0,
                HotelId = hotelId,
                Supplier = supplier,
                SupplierHotelId = supplierHotelId,
                MappingStatus = true,
                UpdatedBy = this.UserId,
                UpdatedByName = this.UserName,
                UpdatedTime = DateTime.Now
            };

            if (await _imappingService.SaveMappingHotel(entity))
            {
                var updateLog = new UpdateLog
                {
                    LogType = UpdateLogType.StaticData,
                    LogSubType = "SaveMapping",
                    LogText = $"Save Mapping, {hotelId}|{supplier}|{supplierHotelId}",
                    BusinessId = hotelId.ToString(),
                    UpdatedBy = this.UserId,
                    UpdatedByName = this.UserName,
                    UpdatedTime = DateTime.Now
                };
                await _iupdateLogService.Add(updateLog);
            }

            return new ResultData<string> { Success = true };
        }

        public async Task<ResultData<int>> AddNewHotel(string supplier, string supplierHotelId)
        {
            var supplierHotel = await _isupplierHotelService.GetHotel(supplier, supplierHotelId);
            if (supplierHotel == null)
                return new ResultData<int> { Success = false, Message = "not find supplier hotel" };

            var hotel = new Hotel { 
                HotelId = 0,
                HotelNameCn = supplierHotel.HotelNameCn,
                HotelNameEn = supplierHotel.HotelNameEn,
                HotelStar = supplierHotel.HotelStar,
                CountryCode = "",
                CountryName = supplierHotel.CountryName,
                ProvinceCode = "",
                ProvinceName = supplierHotel.ProvinceName,
                CityCode = "",
                CityName = supplierHotel.CityName,
                ZoneCode = "",
                ZoneName = supplierHotel.ZoneName,
                HotelAddressCn = supplierHotel.HotelAddressCn,
                HotelAddressEn = supplierHotel.HotelAddressEn,
                Postalcode = supplierHotel.Postalcode,
                HotelLatitude = supplierHotel.HotelLatitude,
                HotelLongitude = supplierHotel.HotelLongitude,
                HotelTel = supplierHotel.HotelTel,
                HotelFax = supplierHotel.HotelFax,
                HotelEmail = supplierHotel.HotelEmail,
                HotelWeb = supplierHotel.HotelWeb,
                HotelStatus = true,
                UpdatedBy = this.UserId,
                UpdatedByName = this.UserName,
                UpdatedTime = DateTime.Now
            };

            var hotelId = await _ihotelService.UpdateHotel(hotel);
            if (hotelId > 0)
            {
                var updateLog = new UpdateLog
                {
                    LogType = UpdateLogType.StaticData,
                    LogSubType = "AddNewHotel",
                    LogText = $"Add New Hotel, {supplier}|{supplierHotelId}|{hotelId}",
                    BusinessId = hotelId.ToString(),
                    UpdatedBy = this.UserId,
                    UpdatedByName = this.UserName,
                    UpdatedTime = DateTime.Now
                };
                await _iupdateLogService.Add(updateLog);

                await _imappingService.SaveMappingHotel(new MappingHotel
                {
                    Id = 0,
                    HotelId = hotelId,
                    Supplier = supplier,
                    SupplierHotelId = supplierHotelId,
                    MappingStatus = true,
                    UpdatedBy = this.UserId,
                    UpdatedByName = this.UserName,
                    UpdatedTime = DateTime.Now
                });

                return new ResultData<int> { Success = true, Data = hotelId};
            }

            return new ResultData<int> { Success = false, Message = "add new hotel failed" };
        }

        public async Task<ResultData<string>> CancelMapping(int hotelId, string supplier, string supplierHotelId)
        {
            if (await _imappingService.DeleteMappingHotel(hotelId, supplier, supplierHotelId))
            {
                var updateLog = new UpdateLog
                {
                    LogType = UpdateLogType.StaticData,
                    LogSubType = "CancelMapping",
                    LogText = $"Cancel Mapping, {hotelId}|{supplier}|{supplierHotelId}",
                    BusinessId = hotelId.ToString(),
                    UpdatedBy = this.UserId,
                    UpdatedByName = this.UserName,
                    UpdatedTime = DateTime.Now
                };
                await _iupdateLogService.Add(updateLog);
            }

            return new ResultData<string> { Success = true };
        }

        public async Task<ResultData<List<VMappingRoom>>> GetRoomMappingList(int HotelId)
        {
            var list = await _imappingService.GetVMappingRooms(HotelId);
            var count = await _imappingService.GetUnMappingRoomCount(HotelId);

            return new ResultData<List<VMappingRoom>>
            {
                Success = true,
                Data = list,
                Message = count.ToString()
            };
        }

        public async Task<ResultData<List<SupplierRoom>>> GetUnMappingRooms(int HotelId)
        {
            var list = await _imappingService.GetUnMappingRooms(HotelId);

            return new ResultData<List<SupplierRoom>>
            {
                Success = true,
                Data = list
            };
        }

        public async Task<ResultData<int>> GetUnMappingRoomCount(int HotelId)
        {
            var count = await _imappingService.GetUnMappingRoomCount(HotelId);

            return new ResultData<int>
            {
                Success = true,
                Data = count
            };
        }

        public async Task<ResultData<string>> SaveRoomMappings([FromBody] MappingRoomDto mappingRoomDto)
        {
            var roomInfo = await _ihotelService.GetRoom(mappingRoomDto.RoomId);
            if(roomInfo == null || !roomInfo.RoomStatus)
                return new ResultData<string> { Success = false, Message = "Room is deleted" };

            if(mappingRoomDto.SupplierRooms.IsEmpty())
                return new ResultData<string> { Success = false, Message = "Supplier Rooms is null" };

            var updateLogList = new List<UpdateLog>();
            var mappingRoomList = new List<MappingRoom>();
            foreach (var supplierRoom in mappingRoomDto.SupplierRooms)
            {
                var supplierRoomInfo = await _isupplierHotelService.GetRoom(supplierRoom.Supplier, supplierRoom.SupplierHotelId, supplierRoom.SupplierRoomId);
                if (supplierRoomInfo != null && supplierRoomInfo.RoomStatus)
                {
                    mappingRoomList.Add(new MappingRoom
                    {
                        HotelId = roomInfo.HotelId,
                        RoomId = roomInfo.RoomId,
                        Supplier = supplierRoom.Supplier,
                        SupplierHotelId = supplierRoom.SupplierHotelId,
                        SupplierRoomId = supplierRoom.SupplierRoomId,
                        MappingStatus = true,
                        UpdatedBy = this.UserId,
                        UpdatedByName = this.UserName,
                        UpdatedTime = DateTime.Now
                    });

                    updateLogList.Add(new UpdateLog
                    {
                        LogType = UpdateLogType.StaticData,
                        LogSubType = "SaveRoomMappings",
                        LogText = $"Save Room Mapping, {roomInfo.RoomId},{roomInfo.RoomNameEn}|{supplierRoom.Supplier},{supplierRoom.SupplierHotelId},{supplierRoom.SupplierRoomId},{supplierRoomInfo.RoomNameEn}",
                        BusinessId = roomInfo.HotelId.ToString(),
                        UpdatedBy = this.UserId,
                        UpdatedByName = this.UserName,
                        UpdatedTime = DateTime.Now
                    });
                }
            }

            if (await _imappingService.SaveRoomMappings(mappingRoomList))
            {
                await _iupdateLogService.Add(updateLogList);
            }

            return new ResultData<string> { Success = true };
        }

        public async Task<ResultData<string>> CancelRoomMapping(int hotelId, string supplier, string supplierHotelId, string supplierRoomId)
        {
            if (await _imappingService.CancelRoomMapping(supplier, supplierHotelId, supplierRoomId))
            {
                var updateLog = new UpdateLog
                {
                    LogType = UpdateLogType.StaticData,
                    LogSubType = "CancelRoomMapping",
                    LogText = $"Cancel Room Mapping, {supplier}|{supplierHotelId}|{supplierRoomId}",
                    BusinessId = hotelId.ToString(),
                    UpdatedBy = this.UserId,
                    UpdatedByName = this.UserName,
                    UpdatedTime = DateTime.Now
                };
                await _iupdateLogService.Add(updateLog);
            }


            return new ResultData<string> { Success = true };
        }
    }
}
